package Account

import (
	"Identity/common"
	"bytes"
	"crypto/ecdsa"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/rlp"
	"sync/atomic"
	"time"
)

/*   ========== 恋爱通证 ===========   */
func NewLoveToken(msg  []byte , aAddr, bAddr common.Address ,starttime ,endtime uint64) *LoveToken {
	return &LoveToken{
		data:TokenData{
			Msg :msg ,
			StartTime:starttime,
			Endtime:endtime,
			AAddress:aAddr,
			BAddress:bAddr,
			digestHash:common.EmptyHash,
		},
	}
}



type LoveToken struct {
	data TokenData


	/*在双方都签名之后生成一个Hash*/
	hash atomic.Value
	size atomic.Value

	Confirmation time.Time `rlp:"-"`//tree_root 提交到ethereum上被确认之后 监听到时间发生时填上该时间
	valid  	   bool		 `rlp:"-"`// 标示当前LoveToken的root是否已经提交到ETH上是否生效  不包含在签名中
}


func NewTokenData() *TokenData{
	return &TokenData{}
}
type TokenData struct {
	Msg        []byte  //爱的誓言

	StartTime  uint64 //开始时间  会在这个时间对感情进行确认 （提交到ETH上)
	Endtime    uint64 //结束时间
	/* 地址和签名 */
	AAddress   common.Address
	BAddress   common.Address

	/*账户随机数*/

	/*TokenData所有属性的哈希值*/
	digestHash common.Hash `rlp:"-"`
	/*对digestHash进行签名*/
	aSigned    []byte  //发起者进行第一次签名  验证：通过公钥计算出私钥对应的地址  aSigned解码的地址 == aAddress 对应的地址
	bSigned    []byte  //接受者进行第二次签名  验证：通过公钥计算出私钥对应的地址  bSigned解码的地址 == bAddress 对应的地址

}

// 计算整个LoveToken.data 的 Hash
func (this * LoveToken)Hash()  common.Hash{
	if hash :=  this.hash.Load() ;hash != nil {
		return hash.(common.Hash)
	}
	v := rlpHash(this.data)
	this.hash.Store(v)

	return v
}



type writerCounter common.StorageSize
func(c * writerCounter) Write(b []byte) (int , error) {
	*c += writerCounter(len(b))
	return len(b),nil
}


func (this * LoveToken)Size() common.StorageSize{
	if size := this.size.Load() ; size!= nil{
		return size.(common.StorageSize)
	}
	c:= writerCounter(0)
	rlp.Encode(&c,&this.data)
	this.size.Store(common.StorageSize(c))
	return common.StorageSize(c)
}

/* 计算TokenData有效数据的rlp编码值*/
func (this * LoveToken)setDigestHash( ) common.Hash{
	//fmt.Println("进入设置DigestHash")
	digesthash := rlpHashTokenData(this)
	this.data.digestHash = digesthash
	return digesthash
}
func (this * LoveToken)getDigestHash( )  common.Hash{
	if this.data.digestHash == common.EmptyHash {
		return this.setDigestHash()
	}
	return this.data.digestHash
}
func (this *LoveToken)ValidDigestHash() bool {
	digesthash := rlpHashTokenData(this)
	return this.data.digestHash == digesthash
}


/* 对TokenData rlp编码进行签名*/
func (this * LoveToken)ASign(Aprv *ecdsa.PrivateKey) error {
	digestHash := this.getDigestHash()
	signature  ,err := crypto.Sign(digestHash[:],Aprv)
	if err != nil{
		return err
	}

	//cpy :=&LoveToken{data:this.data}
	//cpy.aSigned = signature
	this.data.aSigned = signature
	return nil
}


func (this *LoveToken)VerfyASigend( )( bool , error ,common.Address  ){
	digestHash := this.getDigestHash()

	//通过签名信息 获取公钥
	ecdsaPubkey,err  := crypto.SigToPub(digestHash[:],this.data.aSigned)
	if err !=nil{
		return false,err ,common.EmptyAddress
	}
	pub := EcdsaPub2BytePub(*ecdsaPubkey)
	Aaddr := GenerateAddress(pub)
	return bytes.Equal(this.data.AAddress[:],Aaddr[:]) ,nil,Aaddr
}

func (this * LoveToken)BSign(Bprv *ecdsa.PrivateKey) error {
	digestHash := this.getDigestHash()
	signature  ,err := crypto.Sign(digestHash[:],Bprv)
	if err != nil{
		return err
	}
	this.data.bSigned = signature

	return nil
}

func (this * LoveToken)VerifyBSigned()( bool , error ,common.Address  ){
	digestHash := this.getDigestHash()

	//通过签名信息 获取公钥
	ecdsaPubkey,err  := crypto.SigToPub(digestHash[:],this.data.bSigned)
	if err !=nil{
		return false, err ,common.EmptyAddress
	}
	pub := EcdsaPub2BytePub(*ecdsaPubkey)
	Baddr := GenerateAddress(pub)
	return bytes.Equal(this.data.BAddress[:],Baddr[:]) ,nil,Baddr
}

// 判断恋爱通证是否依然有效
func (this *LoveToken)IsValid() bool {
	return this.valid
}


// 对需要RLP编码的数据进行RLP编码
func (this *LoveToken)EncodeRLPToBytes() []byte {
	b,err :=  rlp.EncodeToBytes( &this.data)
	if err != nil{
		panic(err)
	}

	return b
}

func (this *LoveToken)DecodeRLP(rlpBytes []byte )  (retTD *TokenData){
	retTD = &TokenData{}
	err := rlp.DecodeBytes(rlpBytes,retTD)
	if err != nil{
		panic(err)
		return nil
	}

	return
}

func (this * LoveToken)EncodeToRLPBytes() []byte {
	bytes, err := rlp.EncodeToBytes(this.data)
	if err != nil {
		panic(err)
	}

	return bytes
}




// 向交易池提交交易
func (this *LoveToken)CommitOneSignedLTPool(){

}
